#include "BaseType.h"
#include "Tracer.h"
#include "Singleton.h"
#include <map>
using namespace libemb;
/**
 * 享元模式：
 * 1.将对象的内部特征和外部特征进行区分
 * 2.内部特征共享，外部特征定制
 * 3.可以节省大量用于表述对象内部特征的资源
 * 适用场景：
 * 1.系统需要大量相似对象
 * 2.创建对象需要花费大量资源
 **/

//围棋棋子
class GoChess{
DECL_CLASSNAME(GoChess)
public:
    enum Color
    {
        WHITE=0,
        BLACK
    };
public:
    int color()
    {
        return m_color;
    }
    int id()
    {
        return *(int*)this;
    }
protected:
    int m_color;
};

//白棋子
class WhiteChess:public GoChess{
public:
    WhiteChess(){m_color=GoChess::WHITE;}
};

//黑棋子
class BlackChess:public GoChess{
public:
    BlackChess(){m_color=GoChess::BLACK;}
};

//要下的棋
class PlayChess{
DECL_CLASSNAME(PlayChess)
public:
    PlayChess(std::shared_ptr<GoChess> chess):
    m_chess(chess)
    {
    }
    void puton(int x, int y)//放置棋子
    {
        TRACE_DBG_CLASS("put chess[id:0x%08x, color:%d] on pos(%d, %d).",m_chess->id(),m_chess->color(),x,y);
    }
private:
    std::shared_ptr<GoChess> m_chess;
};

//围棋工厂
class GoFactory:public Singleton<GoFactory>{
DECL_CLASSNAME(GoFactory)
DECL_SINGLETON(GoFactory)
private:
    std::map<int,std::shared_ptr<GoChess>> m_chessMap;
public:
    virtual ~GoFactory(){};
    std::shared_ptr<PlayChess> getChess(int color)
    {
        auto iter = m_chessMap.find(color);
        if (iter==m_chessMap.end())
        {
            switch(color){
            case GoChess::BLACK:
            {
                auto chess = std::make_shared<BlackChess>();
                m_chessMap.emplace(std::make_pair(color,std::move(chess)));
                break;
            }
            default:
            {
                auto chess = std::make_shared<WhiteChess>();
                m_chessMap.emplace(std::make_pair(color,std::move(chess)));
                break;
            }
            }
        }
        for(auto& chess: m_chessMap)
        {
            if(chess.second->color()==color)
            {
                return std::make_shared<PlayChess>(chess.second);
            }
        }
    }
};
GoFactory::GoFactory()
{
}



int main()
{
    Tracer::getInstance().setLevel(TRACE_LEVEL_DBG);
	Tracer::getInstance().addSink(std::make_shared<STDSink>()).start();

    auto& goFactory = GoFactory::getInstance();

    auto black01 = goFactory.getChess(GoChess::BLACK);
    black01->puton(1,1);

    auto white01 = goFactory.getChess(GoChess::WHITE);
    white01->puton(18,18);
    
    auto black02 = goFactory.getChess(GoChess::BLACK);
    black02->puton(9,9);

    auto white02 = goFactory.getChess(GoChess::WHITE);
    white02->puton(10,10);
    
    return RC_OK;
}